package com.ybear.ybcomponent.widget;

import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.viewpager.widget.PagerAdapter;

import com.ybear.ybcomponent.OnPageDirectionChangedListener;
import com.ybear.ybcomponent.base.adapter.OnViewPagerAdapterListener;
import com.ybear.ybcomponent.base.adapter.pager.OnVisibleChangedListener;
import com.ybear.ybcomponent.base.adapter.pager.ViewPagerAdapter;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * View切换页面控件
 */
public class ViewPager extends androidx.viewpager.widget.ViewPager {

    private final List<OnPageDirectionChangedListener> mOnPageDirectionList = new ArrayList<>();
    private final List<View> mViews = new ArrayList<>();
    private ViewPagerAdapter<? extends View> mAdapter;

    private boolean isEnableScroll = true;
    private boolean isEnableVisibleChanged = false;
    private int mOldPosition = -1;
    private float mOldOffset = -1;

    private OnViewPagerAdapterListener mOnViewPagerAdapterListener;

    public ViewPager(@NonNull Context context) {
        this(context, null);
    }

    public ViewPager(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        addOnPageChangeListener(new OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float offset, int offsetPixels) {
                if( mOldOffset == -1 ) mOldOffset = offset;
                if( offset > 0 ) {
                    if( mOldOffset < offset ) {
                        //Right
                        onPageDirection( position, offset, offsetPixels, 1 );
                    }else if( mOldOffset > offset ) {
                        //Lift
                        onPageDirection( position, offset, offsetPixels, 0 );
                    }
                }
                mOldOffset = offset;
            }
            @Override
            public void onPageSelected(int position) {
//                if( mOldPosition == -1 ) mOldPosition = position;
                doOldPosition( 0 );
                if( mOldPosition <= position ) {
                    //Right
                    onPageDirection( position, mOldPosition, 1 );
                }else {
                    //Lift
                    onPageDirection( position, mOldPosition, 0 );
                }
                mOldPosition = position;
            }
            @Override
            public void onPageScrollStateChanged(int state) {
                for( OnPageDirectionChangedListener l : mOnPageDirectionList ) {
                    if( l != null ) l.onPageDirectionChanged( state );
                }
            }
        });
    }

    public void setOnViewPagerAdapterListener(OnViewPagerAdapterListener l) {
        mOnViewPagerAdapterListener = l;
        if( mAdapter != null ) mAdapter.setOnViewPagerAdapterListener( mOnViewPagerAdapterListener );
    }

    @Override
    public void setCurrentItem(int item) {
        super.setCurrentItem(item);
        doOldPosition( getCurrentItem() );
    }

    @Override
    public void setCurrentItem(int item, boolean smoothScroll) {
        super.setCurrentItem(item, smoothScroll);
        doOldPosition( getCurrentItem() );
    }

    private void doOldPosition(int position) {
        if( mOldPosition == -1 ) mOldPosition = position;
    }

    @SuppressLint("ClickableViewAccessibility")
    @Override
    public boolean onTouchEvent(MotionEvent ev) { return isEnableScroll && super.onTouchEvent(ev); }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return isEnableScroll && super.onInterceptTouchEvent(ev);
    }

    public <V extends View> boolean setViewsOfPager(@NonNull List<V> list) {
        clearViewOfPager();
        return mViews.addAll( list );
    }

    @SafeVarargs
    public final <V extends View> boolean setViewsOfPager(@NonNull V... f) {
        return setViewsOfPager( Arrays.asList( f ) );
    }

    public <V extends View> boolean addViewOfPager(@NonNull V v) {
        return mViews.add( v );
    }

    public <V extends View> ViewPager addViewOfPager(int index, @NonNull V v) {
        mViews.add( index, v );
        return this;
    }

    public <V extends View> boolean addViewAllOfPager(@NonNull List<V> list) {
        return mViews.addAll( list );
    }

    public <V extends View> boolean addViewAllOfPager(int index, @NonNull List<V> list) {
        return mViews.addAll( index, list );
    }

    public <V extends View> boolean removeViewOfPager(@NonNull V v) {
        boolean ret = mViews.remove( v );
        if( mViews.size() == 0 ) reset();
        return ret;
    }

    public View removeViewOfPager(int index) {
        View f = mViews.remove( index );
        if( mViews.size() == 0 ) reset();
        return f;
    }

    public void clearViewOfPager() {
        mViews.clear();
        reset();
    }

    /**
     * 获取数据源适配器
     * @return  适配器
     */
    public ViewPagerAdapter<? extends View> getAdapter() { return mAdapter; }

    @Deprecated
    @Override
    public void setAdapter(@Nullable PagerAdapter adapter) {
//        super.setAdapter(adapter);
    }

    public void setAdapter(@Nullable ViewPagerAdapter<? extends View> adapter) {
        mAdapter = adapter;
        notifyAdapter();
    }

    /**
     * 设置完毕后进行创建适配器等操作
     */
    public void notifyAdapter() {
        if( mAdapter == null ) {
            super.setAdapter( mAdapter = new ViewPagerAdapter<>( mViews ) );
        }
        mAdapter.setOnViewPagerAdapterListener( mOnViewPagerAdapterListener );
        mAdapter.notifyDataSetChanged();
    }

    /**
     * 是否启用滑动
     * @param enable    是否启用
     * @return          this
     */
    public ViewPager setEnableScroll(boolean enable) {
        isEnableScroll = enable;
        return this;
    }
    public boolean isEnableScroll() { return isEnableScroll; }

    /**
     * 启用/禁用View可见/不可见时通知
     * 启用后需要在View中实现 {@link OnVisibleChangedListener}
     * @param enable    是否启用
     */
    public ViewPager setEnableVisibleChanged(boolean enable) {
        isEnableVisibleChanged = enable;
        return this;
    }
    public boolean isEnableVisibleChanged() { return isEnableVisibleChanged; }

    /**
     * 获取所有View列表
     * @return  列表
     */
    @NonNull
    public List<View> getViewList() { return new ArrayList<>( mViews ); }

    /**
     * 获取指定位置的View
     * @param position  下标
     * @return          View
     */
    public View getView(int position) {
        return checkPosition( position ) ? mViews.get( position ) : null;
    }

    /**
     * 获取View数量
     * @return  数量
     */
    public int getViewCount() { return mViews.size(); }

    /**
     * 添加滑动方向改变事件监听器
     * @param l 监听器
     */
    public void addOnPageDirectionChangedListener(OnPageDirectionChangedListener l) {
        mOnPageDirectionList.add( l );
    }

    /**
     * 移除滑动方向改变事件监听器
     * @param l 监听器
     */
    public void removeOnPageDirectionChangedListener(OnPageDirectionChangedListener l) {
        mOnPageDirectionList.remove( l );
    }

    /**
     * 滑动方向改变
     * @param position                  下标
     * @param positionOffset            滑动小数级偏移
     * @param positionOffsetPixels      滑动像素级偏移
     * @param direction                 滑动方向
     */
    private void onPageDirection(int position, float positionOffset, int positionOffsetPixels,
                                 int direction) {
        for( OnPageDirectionChangedListener l : mOnPageDirectionList ) {
            if( l == null ) return;
            l.onPageDirection( position, positionOffset, positionOffsetPixels, direction );
        }
    }
    private void onPageDirection(int position, int oldPosition, int direction) {
        //通知页面位置发生改变
        for( OnPageDirectionChangedListener l : mOnPageDirectionList ) {
            if( l != null ) l.onPageDirection( position, oldPosition, direction );
        }
    }

    private void reset() {
        mOldOffset = -1;
        mOldPosition = -1;
    }

    private boolean checkPosition(int position) {
        return position >= 0 && position < mViews.size();
    }
}
